home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / comm / msg10.sit / MSG Watcher.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-12-05  |  18.7 KB  |  910 lines  |  [TEXT/KAHL]

  1. /*
  2.  * Mac Workstation exec to watch incomming and outgoing Mac Workstation
  3.  * message traffic
  4.  * The project type must be code resource
  5.  * Check the box for custom header in the project type
  6.  * Created 12:45:39 AM  10/26/89 by Aaron Wohl, aw0g+@andrew.cmu.edu
  7.  * Aaron Wohl
  8.  * 6393 Penn Ave #303
  9.  * Pittsburgh PA,15206
  10.  * home:(412)731-6159
  11.  * work:(412)268-5032
  12.  * Do what you will with it
  13.  * See MWS_EXEC.c for how to build this
  14.  * Probably needs LightspeedC 4.0, haven't tried 3.xx
  15.  */
  16.  
  17. /*configuration constants*/
  18. /*min ticks between scroll operations, makes scroll slow enough to use on 68030*/
  19. #define MIN_SCROLL_TIME (4)
  20.  
  21. /* define USE_MEM_RATHER_THAN_STACK as desired*/
  22.  
  23. /*
  24.  * expand the lick point this many pixels to obtain the area
  25.  * considered to be the same for clicking to determine double clicks
  26.  */
  27. #define CLICK_IN_SAME_SPOT (1)
  28.  
  29. #include "mws.h"
  30. #include "mws_exec.h"
  31.  
  32. #define NIL 0L
  33. #define TRUE (0==0)
  34. #define FALSE (0==1)
  35. #define SBarWidth 16
  36. #define DELCH (8)        /*character for deleting*/
  37. #define imax(xx_1,xx_2) (((xx_1)>(xx_2))?(xx_1):(xx_2))
  38. #define imin(xx_1,xx_2) (((xx_1)<(xx_2))?(xx_1):(xx_2))
  39.  
  40. struct watcher_globals_R {
  41.     Rect LastKnownSize;
  42.     WindowPtr win;
  43.     ControlHandle vScroll;
  44.     TEHandle TEH;
  45.     int LinesInView;
  46.     int AreActive;
  47.     RgnHandle save_clip_in_auto_scroll;
  48.     char **send_me;        /*message we are transmiting from paste*/
  49.     int apply_speed_limit;
  50. };
  51. typedef struct watcher_globals_R watcher_globals,*watcher_globals_pt;
  52.  
  53. watcher_globals gl;
  54.  
  55. #define MAKE_WINDOW_IF_NEEDED {if(gl.win==NIL)create_window(xecRef);}
  56.  
  57. void SetVScrollMax(void);
  58. void SetVScrollMax()
  59. {
  60.     register int n;
  61.     /*get line number of top line*/
  62.     n = (*gl.TEH)->nLines-gl.LinesInView;
  63.  
  64.     /*count correctly if last line is terminated*/
  65.     if ((*gl.TEH)->teLength > 0 &&
  66.          (*((*gl.TEH)->hText))[(*gl.TEH)->teLength-1]=='\r')
  67.         n++;
  68.     n=imax(0,n);
  69.     if(GetCtlMax(gl.vScroll)!=n)
  70.         SetCtlMax(gl.vScroll,n);
  71. }
  72.  
  73. void ScrollTextToMatchControl(void);
  74. void ScrollTextToMatchControl()
  75. {
  76.     int        oldScroll, newScroll, delta;
  77.  
  78.     oldScroll = (*gl.TEH)->viewRect.top - (*gl.TEH)->destRect.top;
  79.     newScroll = GetCtlValue(gl.vScroll) * (*gl.TEH)->lineHeight;
  80.     delta = oldScroll - newScroll;
  81.     if (delta != 0)
  82.       TEScroll(0, delta,gl.TEH);
  83. }
  84.  
  85. void SetCtlLoc(int newloc);
  86. void SetCtlLoc(int newloc)
  87. {
  88.     /*don't scroll too fast on fast machines*/
  89.     if(++gl.apply_speed_limit !=0) {
  90.         static long last_scroll_time=0;
  91.         long now;
  92.         long dif;
  93.         now=TickCount();
  94.         dif=now-last_scroll_time;
  95.         if(dif<MIN_SCROLL_TIME)
  96.             return;
  97.         last_scroll_time=now;
  98.     }
  99.  
  100.     {int max=GetCtlMax(gl.vScroll);
  101.     /*don't set the ctl value if it hasn't changed, it causes flickering*/
  102.     newloc=imax(0,newloc);
  103.     newloc=imin(newloc,max);
  104.     if(newloc==GetCtlValue(gl.vScroll))
  105.         return;
  106.     SetCtlValue(gl.vScroll,newloc);
  107.     ScrollTextToMatchControl();
  108.     }
  109. }
  110.  
  111. void ScrollSelectionIntoView(void);
  112. void ScrollSelectionIntoView()
  113. {
  114.     register int topLine, bottomLine, theLine;
  115.     
  116.     SetVScrollMax();
  117.     ScrollTextToMatchControl();
  118.     
  119.     topLine = GetCtlValue(gl.vScroll);
  120.     bottomLine = topLine + gl.LinesInView-1;
  121.     
  122.     if ((*gl.TEH)->selStart < (*gl.TEH)->lineStarts[topLine] ||
  123.             (*gl.TEH)->selStart >= (*gl.TEH)->lineStarts[bottomLine]) {
  124.         for (theLine = 0; (*gl.TEH)->selStart >= (*gl.TEH)->lineStarts[theLine]; theLine++)
  125.             ;
  126.         SetCtlLoc(theLine - gl.LinesInView / 2);
  127.     }
  128. }
  129.  
  130. void make_wm_window(THExecRef xecRef);
  131. void make_wm_window(THExecRef xecRef)
  132. {
  133.     Rect bounds;
  134.     SetRect(&bounds,5,45,500,200);
  135.     gl.win=NewWindow(
  136.         NIL,
  137.         &bounds,
  138.         "\pCMU MSG Watcher",
  139.         TRUE,
  140.         8,
  141.         ((WindowPtr)-1L),
  142.         TRUE,
  143.         ((long)xecRef));
  144.     ((WindowPeek)gl.win)->windowKind=wExec;
  145.     (*xecRef)->xOptions=
  146.         (xCallIdle|xCallKey|xCallSend|xCallFilter|
  147.         xCallReceive|xCallMouse|xCallStdMenuEvt);
  148.     SetPort(gl.win);
  149.     gl.AreActive=TRUE;
  150. }
  151.  
  152. void SetView(void);
  153. void SetView()
  154. {
  155.     (*gl.TEH)->viewRect = gl.win->portRect;
  156.     (*gl.TEH)->viewRect.right -= SBarWidth;
  157.     InsetRect(&(*gl.TEH)->viewRect, 4, 4);
  158.     gl.LinesInView = ((*gl.TEH)->viewRect.bottom-(*gl.TEH)->viewRect.top)/(*gl.TEH)->lineHeight;
  159.     (*gl.TEH)->destRect.right = (*gl.TEH)->viewRect.right;
  160.     TECalText(gl.TEH);
  161. }
  162.  
  163. void WindowSizeHasChanged(void);
  164. void WindowSizeHasChanged(void)
  165. {
  166.     Rect SafeRect;
  167.     SafeRect=(*gl.vScroll)->contrlRect;
  168.     InvalRect(&SafeRect);
  169.     MoveControl(
  170.         gl.vScroll,
  171.         gl.win->portRect.right-SBarWidth+1,
  172.         -1);
  173.     SizeControl(
  174.         gl.vScroll,
  175.         SBarWidth,
  176.         ((gl.win->portRect.bottom-gl.win->portRect.top)-SBarWidth)+3);
  177.     InvalRect(&SafeRect);
  178.     SetView();
  179.     SetVScrollMax();
  180. }
  181.  
  182. void RealScrollProc(ControlHandle theControl,int theCode);
  183. void RealScrollProc(ControlHandle theControl,int theCode)
  184. {
  185.     int    pageSize;
  186.     int    scrollAmt;
  187.  
  188.     if (theCode == 0)
  189.         return ;
  190.  
  191.     pageSize = ((*gl.TEH)->viewRect.bottom-(*gl.TEH)->viewRect.top) / 
  192.             (*gl.TEH)->lineHeight - 1;
  193.             
  194.     switch (theCode) {
  195.         case inUpButton: 
  196.             scrollAmt = -1;
  197.             break;
  198.         case inDownButton: 
  199.             scrollAmt = 1;
  200.             break;
  201.         case inPageUp: 
  202.             scrollAmt = -pageSize;
  203.             break;
  204.         case inPageDown: 
  205.             scrollAmt = pageSize;
  206.             break;
  207.         }
  208.     SetCtlLoc(GetCtlValue(theControl)+scrollAmt);
  209. }
  210.  
  211. void RealAutoScrollProc(void);
  212. void RealAutoScrollProc()
  213. {
  214.     Point here;
  215.     GrafPtr savePort;
  216.     GetPort(&savePort);
  217.     GetClip(gl.save_clip_in_auto_scroll);
  218.     SetPort(gl.win);
  219.     ClipRect(&gl.win->portRect);
  220.     GetMouse(&here);
  221.     if(here.v<(*gl.TEH)->viewRect.top)
  222.         RealScrollProc(gl.vScroll,inUpButton);
  223.     else if(here.v>=(*gl.TEH)->viewRect.bottom)
  224.         RealScrollProc(gl.vScroll,inDownButton);
  225.     SetClip(gl.save_clip_in_auto_scroll);
  226.     SetPort(savePort);
  227. }
  228.  
  229. pascal void ScrollProc(ControlHandle theControl,int theCode);
  230. pascal void ScrollProc(ControlHandle theControl,int theCode)
  231. {
  232.     /*since this is a call back need to set proper register to
  233.       access our globals
  234.     */
  235.     asm {
  236.         move.l a4,-(sp)
  237.         lea proper_a4,a4
  238.     }
  239.     RealScrollProc(theControl,theCode);
  240.     asm {move.l (sp)+,a4}
  241. }
  242.  
  243. pascal int AutoScrollProc(void);
  244. pascal int AutoScrollProc(void)
  245. {
  246.     /*since this is a call back need to set proper register to
  247.       access our globals
  248.     */
  249.     asm {
  250.         move.l a4,-(sp)
  251.         lea proper_a4,a4
  252.     }
  253.     RealAutoScrollProc();
  254.     asm {move.l (sp)+,a4}
  255.     return TRUE;
  256. }
  257.  
  258. /*bit table of characters that have printing width*/
  259. #define BITS_PER_ENTRY (sizeof(long)*8)
  260. long ok_ch[256/BITS_PER_ENTRY];
  261.  
  262. #define OK_IN_DISPLAY(xx_arg) \
  263.     {ok_ch[(xx_arg)/BITS_PER_ENTRY]|=(1L<<((xx_arg)%BITS_PER_ENTRY));}
  264.  
  265. void set_widths(void);
  266. void set_widths()
  267. {
  268.     int i;
  269.     for(i=' ';i<0x7f;i++)
  270.         OK_IN_DISPLAY(i);
  271.     OK_IN_DISPLAY('\r');
  272. }
  273.  
  274. /* insert a string that might have some
  275.  * unprintable characters
  276.  */
  277. void insert_nasty_string(char *astr,int len);
  278. void insert_nasty_string(astr,len)
  279. register char *astr;
  280. register int len;
  281. {
  282.     /* **MAKE THIS static TO TRADE STACK SPACE INTO PERMINANT SPACE** */
  283.     char
  284. #ifdef USE_MEM_RATHER_THAN_STACK
  285.         static
  286. #endif
  287.         buf[4*kMsgMaxData+10];
  288.     register char *dst=buf;
  289.     register unsigned char ch;
  290.     static char octal_digit[8]="01234567";
  291.     static previous_string_ended_in_cr=FALSE;
  292.     if(len==0)return;
  293.     if(previous_string_ended_in_cr) {
  294.         *dst++='\r';
  295.         previous_string_ended_in_cr=FALSE;
  296.     }
  297.     while(--len >=0) {
  298.         ch=*astr++;
  299.         if(ch=='\\') {
  300.             *dst++='\\';
  301.             *dst++='\\';
  302.         }else if((ok_ch[ch/BITS_PER_ENTRY]&(1L<<(ch%BITS_PER_ENTRY)))!=0)
  303.             *dst++=ch;
  304.         else {
  305.             register int adigit;
  306.             *dst++='\\';
  307.             adigit=ch/0100;
  308.             ch-=adigit*0100;
  309.             *dst++=octal_digit[adigit];
  310.             adigit=ch/0010;
  311.             ch-=adigit*0010;
  312.             *dst++=octal_digit[adigit];
  313.             *dst++=octal_digit[ch];
  314.         }
  315.     }
  316.     len=dst-buf;
  317.     if(buf[len-1]=='\r') {
  318.         previous_string_ended_in_cr=TRUE;
  319.         len--;
  320.     }
  321.     if(len!=0)
  322.          TEInsert(buf,len,gl.TEH);
  323. }
  324.  
  325. void install_window_contents(void);
  326. void install_window_contents()
  327. {
  328.     Rect vScrollRect;
  329.     Rect viewRect;
  330.     gl.save_clip_in_auto_scroll=NewRgn();
  331.     TextFont(4);
  332.     TextSize(9);
  333.     vScrollRect=gl.win->portRect;
  334.     vScrollRect.left=vScrollRect.right-15;
  335.     vScrollRect.right+=1;
  336.     vScrollRect.bottom-=14;
  337.     vScrollRect.top-=1;
  338.     gl.vScroll=NewControl(gl.win,&vScrollRect,"\p",1,0,0,0,
  339.         scrollBarProc, 0L);
  340.  
  341.     viewRect=gl.win->portRect;
  342.     viewRect.right-=SBarWidth;
  343.     viewRect.bottom-=SBarWidth;
  344.     InsetRect(&viewRect,4,4);
  345.     gl.TEH=TENew(&viewRect,&viewRect );
  346.     SetView();
  347.     (*gl.TEH)->clikLoop=AutoScrollProc;
  348.     set_widths();
  349. }
  350.  
  351. void create_window(THExecRef xecRef);
  352. void create_window(THExecRef xecRef)
  353. {
  354.     make_wm_window(xecRef);
  355.     install_window_contents();
  356. }
  357.  
  358.  
  359. void doIdle(THExecRef xecRef);
  360. void doIdle(xecRef)
  361. THExecRef xecRef;
  362. {
  363. #ifdef XXXYYY
  364.     user iterface guid says read only windows don't blink intsert bar
  365.     TEIdle(gl.TEH);
  366. #endif
  367.     if((gl.win->portRect.bottom!=gl.LastKnownSize.bottom)||
  368.         (gl.win->portRect.right!=gl.LastKnownSize.right)||
  369.         (gl.win->portRect.top!=gl.LastKnownSize.top)||
  370.         (gl.win->portRect.right!=gl.LastKnownSize.right)) {
  371.         gl.LastKnownSize=gl.win->portRect;
  372.         WindowSizeHasChanged();
  373.     }
  374. }
  375.  
  376. #define TRIM_TRIGGER_SIZE (29000)
  377. #define TRIM_HYSTERYSYS (6000)
  378.  
  379. /*
  380.  * cut some data off the start of a handle
  381.  * returns true if it is now empty
  382.  */
  383. int trim_handle(Handle ahan,int shorten_amount);
  384. int trim_handle(Handle ahan,int shorten_amount)
  385. {
  386.     int new_size=GetHandleSize(ahan)-shorten_amount;
  387.     register char *src;
  388.     register char *dst;
  389.     register int i;
  390.     dst=(*ahan);
  391.     src=dst+shorten_amount;
  392.     for(i=0;i<new_size;i++)
  393.         *dst++=*src;
  394.     SetHandleSize(gl.TEH,new_size);
  395. }
  396.  
  397. void append_to_log(char *astr,int len);
  398. void append_to_log(char *astr,int len)
  399. {
  400.     int buflen;
  401.     buflen=(*gl.TEH)->teLength;
  402.     if(buflen>TRIM_TRIGGER_SIZE) {
  403.         trim_handle((*gl.TEH)->hText,TRIM_HYSTERYSYS);
  404.         TECalText(gl.TEH);
  405.         buflen=(*gl.TEH)->teLength;
  406.     }
  407.        TESetSelect(buflen,buflen,gl.TEH);
  408.        insert_nasty_string(astr,len);
  409.      gl.apply_speed_limit= -1;    /*speed limit doesn't apply to insert*/
  410.      ScrollSelectionIntoView();
  411. }
  412.  
  413. long strnchr(char *astr,char ch,long limit);
  414. long strnchr(astr,ch,limit)
  415. register char *astr;
  416. register char ch;
  417. register long limit;
  418. {
  419.     char *orig_astr=astr;
  420.     while(limit-- >0) {
  421.         if(*astr++ ==ch)
  422.             return astr-orig_astr-1;
  423.     }
  424.     return -1;
  425. }
  426.  
  427. long strlen(char *astr);
  428. long strlen(astr)
  429. register char *astr;
  430. {
  431.     register long result=0;
  432.     while(*astr++ !=0)
  433.         result++;
  434.     return result;
  435. }
  436.  
  437. void cat_to_log(char *astr);
  438. void cat_to_log(char *astr)
  439. {
  440.   append_to_log(astr,strlen(astr));
  441. }
  442.  
  443. void report_msg(char *kind,THExecRef xecRef);
  444. void report_msg(char *kind,THExecRef xecRef)
  445. {
  446.     char buf[kMsgMaxData+20];
  447.     register char *dst=buf;
  448.     register char *src=(*xecRef)->xMsg->msgData;
  449.     register char ch;
  450.     register int i;
  451.       if(!((*xecRef)->xMsg->msgValid))
  452.           return;
  453.       while ((ch=*kind++)!=0)
  454.           *dst++=ch;
  455.       for(i=(*xecRef)->xMsg->msgLength;i>0;i--)
  456.           *dst++=*src++;
  457.       *dst++='\r';
  458.       append_to_log(buf,dst-buf);
  459. }
  460.  
  461. void doSend(THExecRef xecRef);
  462. void doSend(xecRef)
  463. THExecRef xecRef;
  464. {
  465.     if(gl.win==NIL)return;
  466.     report_msg(">",xecRef);
  467. }
  468.  
  469. void doReceive(THExecRef xecRef);
  470. void doReceive(xecRef)
  471. THExecRef xecRef;
  472. {
  473.     if(gl.win==NIL)return;
  474.     report_msg("<",xecRef);
  475. }
  476.  
  477. void doFilter(THExecRef xecRef);
  478. void doFilter(xecRef)
  479. THExecRef xecRef;
  480. {
  481.     if(gl.win==NIL)return;
  482.     report_msg("<",xecRef);
  483. }
  484.  
  485. /*
  486.  * This isn't a resource to make
  487.  * installing it simpler
  488.  */
  489. char help_text[]=
  490.  "! CMU Mac Workstation message watcher\r"
  491.  "! by Aaron Wohl, aw0g+@andrew.cmu.edu (412)268-5032\r"
  492.  "! cmd-c       => copy to clip board stripping leading '<' and '>'\r"
  493.  "! cmd-c-shift => copy to clip don't strip leading '<' and '>'\r"
  494.  "! cmd-v       => Paste to local macworktation\r"
  495.  "! cmd-v-shift => Paste to server host\r"
  496.  "! cmd-h       => This help message\r"
  497.  "! start me in ccl logon script to see all messages eg 'Exec 200'\r"
  498.  ;
  499.  
  500. void help(void);
  501. void help()
  502. {
  503.     cat_to_log(help_text);
  504. }
  505.  
  506. void doInvoke(THExecRef xecRef);
  507. void doInvoke(xecRef)
  508. THExecRef xecRef;
  509. {
  510.     MAKE_WINDOW_IF_NEEDED
  511.     if(gl.win==NIL)return;
  512.     help();
  513. }
  514.  
  515. void close_window(void);
  516. void close_window()
  517. {
  518.  if(gl.TEH!=0)
  519.    TEDispose(gl.TEH);
  520.  gl.TEH=0;
  521.  
  522.  if(gl.win!=NIL)
  523.    DisposeWindow(gl.win);
  524.  gl.win=NIL;
  525.  gl.AreActive=FALSE;
  526. }
  527.  
  528.  
  529. void doUnload(THExecRef xecRef);
  530. void doUnload(xecRef)
  531. THExecRef xecRef;
  532. {
  533.     close_window();
  534. }
  535.  
  536. void doCommand(THExecRef xecRef);
  537. void doCommand(xecRef)
  538. THExecRef xecRef;
  539. {
  540.     MAKE_WINDOW_IF_NEEDED
  541.     if(gl.win==NIL)return;
  542.     report_msg("*",xecRef);
  543. }
  544.  
  545. void doActivate(THExecRef xecRef);
  546. void doActivate(xecRef)
  547. THExecRef xecRef;
  548. {
  549.     Rect r;
  550.     r=(*gl.win).portRect;
  551.     r.top=r.bottom - (SBarWidth+1);
  552.     r.left=r.left - (SBarWidth+1);
  553.     InvalRect(&r);
  554.     gl.AreActive=(*xecRef)->xActive;
  555.     if(gl.AreActive) {
  556.         TEActivate(gl.TEH);
  557.         ShowControl(gl.vScroll);
  558.         TEFromScrap();
  559.     } else {
  560.         TEDeactivate(gl.TEH);
  561.         HideControl(gl.vScroll);
  562.         ZeroScrap();
  563.         TEToScrap();
  564.     }
  565. }
  566.  
  567. void draw_grow_with_no_horizontial_scroll(void);
  568. void draw_grow_with_no_horizontial_scroll()
  569. {
  570.     Rect new_clip;
  571.     GetClip(gl.save_clip_in_auto_scroll);
  572.     new_clip=gl.win->portRect;
  573.     new_clip.left=new_clip.right-SBarWidth+1;
  574.     ClipRect(&new_clip);
  575.     DrawGrowIcon(gl.win);
  576.     SetClip(gl.save_clip_in_auto_scroll);
  577. }
  578.  
  579. void doDraw(THExecRef xecRef);
  580. void doDraw(xecRef)
  581. THExecRef xecRef;
  582. {
  583.     WindowPtr theWindow;
  584.     theWindow=(*xecRef)->xWindow;
  585.     if(theWindow!=gl.win)
  586.         SysBeep(20);
  587.     BeginUpdate(theWindow);
  588.     /* EraseRect(&theWindow->portRect); */
  589.     EraseRect(&theWindow->portRect);
  590.     DrawControls(gl.win);
  591.     TEUpdate(&gl.win->portRect,gl.TEH);
  592.     draw_grow_with_no_horizontial_scroll();
  593.     EndUpdate(theWindow);
  594. }
  595.  
  596. char ftolower(char ch);
  597. char ftolower(char ch)
  598. {
  599.     if((ch>='A')&&(ch<='Z'))
  600.         ch+=('a'-'A');
  601.     return ch;
  602. }
  603.  
  604.  
  605. void UsedEvent(THExecRef xecRef);
  606. void UsedEvent(THExecRef xecRef)
  607. {
  608.     (*xecRef)->xEvent->what=nullEvent;
  609.     (*xecRef)->xKey=0;
  610. }
  611.  
  612. /*
  613.  * Filter out the < and > characters in buffer
  614.  */
  615. void FixTEScrap(void);
  616. void FixTEScrap()
  617. {
  618.     register char *src;
  619.     register char *dst;
  620.     register long len;
  621.     long new_len=0;
  622.     register char ch;
  623.     len=TEGetScrapLen();
  624.     src=dst=(*TEScrapHandle());
  625. #define GetCH {if(--len <0)goto FixTEExit; ch=*src++;}
  626.     while (TRUE) {
  627.         GetCH
  628.         if((ch=='>')||(ch=='<'))
  629.           GetCH;
  630.         while(ch!='\r') {
  631.             *dst++=ch;
  632.             new_len++;
  633.             GetCH
  634.         }
  635.         *dst++=ch;
  636.         new_len++;
  637.     };
  638. #undef GetCH
  639.     FixTEExit:
  640.         TESetScrapLen(new_len);
  641. }
  642.  
  643. /*
  644.  * prepare the next message for transmision
  645.  */
  646. int extract_msg_from_scrap(TPMsg out);
  647. int extract_msg_from_scrap(out)
  648. register TPMsg out;
  649. {
  650.     register char *dst;
  651.     register char *src;
  652.     long len;
  653.     long i;
  654.     if(gl.send_me==0)return FALSE;
  655.     len=GetHandleSize(gl.send_me);
  656.     if(len<=0) {
  657.         DisposHandle(gl.send_me);
  658.         gl.send_me=0;
  659.         return FALSE;
  660.     }
  661.     i=strnchr(*gl.send_me,'\r',len);
  662.     if(i==-1) {        /*no return so use rest of buffer*/
  663.         i=len;
  664.         len=0;
  665.     } else 
  666.         len-=i+1;    /*consume str including cr, but don't send it*/
  667.     i=imin(i,kMsgMaxData);
  668.     BlockMove((*gl.send_me),out->msgData,i);
  669.     out->msgIndex=0;
  670.     out->msgLength=i;
  671.     out->msgValid=TRUE;
  672.     if(len<=0) {
  673.         DisposHandle(gl.send_me);
  674.         gl.send_me=0;
  675.     } else
  676.         trim_handle(gl.send_me,i);
  677.     return TRUE;
  678. }
  679.  
  680. /*
  681.  * Emit the text in the te scrap as in comming message
  682.  * to macworkstation or an outgoing message to the host
  683.  */
  684. void EmitScrap(THExecRef xecRef,int to_host);
  685. void EmitScrap(THExecRef xecRef,int to_host)
  686. {
  687.     char **to_send;
  688.  
  689.     if(gl.send_me!=0) {
  690.         SysBeep(20);
  691.         cat_to_log("! Sorry, a message paste is still in progress\r");
  692.         return;
  693.     }
  694.     to_send=TEScrapHandle();
  695.     if(HandToHand(&to_send)!=0) {
  696.         SysBeep(20);
  697.         cat_to_log("! Sorry, can't get memory for message paste\r");
  698.         return;
  699.     }
  700.     SetHandleSize(to_send,TEGetScrapLen());
  701.     gl.send_me=to_send;
  702.     {
  703.         TRMsg m;
  704.         while (extract_msg_from_scrap(&m))
  705.             if(to_host)
  706.                 MWS_Send(&m,xecRef);
  707.             else
  708.                 MWS_Command(&m,xecRef);
  709.     }
  710. }
  711.  
  712. void doCmdKey(THExecRef xecRef);
  713. void doCmdKey(xecRef)
  714. THExecRef xecRef;
  715. {
  716.     char cmd_ch;
  717.     cmd_ch=((*xecRef)->xEvent->message)& 0xFF;
  718.     cmd_ch=ftolower(cmd_ch);
  719.     switch(cmd_ch) {
  720.     case 'c':
  721.         TECopy(gl.TEH);
  722.         UsedEvent(xecRef);
  723.         if(((*xecRef)->xEvent->modifiers & shiftKey)==0)
  724.             FixTEScrap();
  725.         break;
  726.     case 'v':
  727.         EmitScrap(xecRef,((*xecRef)->xEvent->modifiers & shiftKey)!=0);
  728.         UsedEvent(xecRef);
  729.         break;
  730.     case 'h':
  731.         help();
  732.         UsedEvent(xecRef);
  733.         break;
  734.     default:
  735.         break;
  736.     }
  737. }
  738.  
  739. void doKey(THExecRef xecRef);
  740. void doKey(xecRef)
  741. THExecRef xecRef;
  742. {
  743.     if(!gl.AreActive)return;
  744.     if(((*xecRef)->xEvent->modifiers & cmdKey)!=0)
  745.         doCmdKey(xecRef);
  746.     else {
  747.         SysBeep(20);
  748.         UsedEvent(xecRef);
  749.     }
  750. }
  751.  
  752. long last_click_time=0;
  753.  
  754. void not_double(void);
  755. void not_double()
  756. {
  757.     last_click_time=0;
  758. }
  759.  
  760. int is_double(Point here);
  761. int is_double(Point here)
  762. {
  763.     long now=TickCount();
  764.     static Rect click_local;
  765.     static int dcount;
  766.     int result;
  767.     if(!PtInRect(here,&click_local))
  768.         last_click_time=0;
  769.     topLeft(click_local)=here;
  770.     botRight(click_local)=here;
  771.     InsetRect(&click_local,-CLICK_IN_SAME_SPOT,-CLICK_IN_SAME_SPOT);
  772.  
  773.     if((now-last_click_time)<GetDblTime())
  774.         dcount++;
  775.     else
  776.         dcount=1;
  777.  
  778.     last_click_time=now;
  779.  
  780.     result=dcount;
  781.     if(dcount>=3)
  782.         dcount=0;
  783.  
  784.     return result;
  785. }
  786.  
  787. void select_line(void);
  788. void select_line()
  789. {
  790.     register int sel_start=(*gl.TEH)->selStart;
  791.     register int sel_end=sel_start;
  792.     register char *src;
  793.  
  794.     /*extend selection back to start of line*/
  795.     if(sel_start!=0) {
  796.         src=(*(*gl.TEH)->hText)+sel_start;
  797.         do {
  798.             if(*--src == '\r')
  799.                 goto found_start;
  800.             } while(--sel_start>=0);
  801.             sel_start=0;
  802.     }
  803.     found_start:
  804.  
  805.     /*extend selection forward to end of line*/
  806.     if(sel_end!=0) {
  807.         int size=(*gl.TEH)->teLength;
  808.         src=(*(*gl.TEH)->hText)+sel_end;
  809.         do {
  810.             if(*src++ == '\r')
  811.                 goto found_end;
  812.             } while(sel_end++<size);
  813.             sel_end=size;
  814.     }
  815.  
  816.     found_end:
  817.     TESetSelect(sel_start,sel_end,gl.TEH);
  818. }
  819.  
  820. void do_teclick(int double_count,Point here,int shift);
  821. void do_teclick(int double_count,Point here,int shift)
  822. {
  823.     if(double_count>=3) {
  824.         select_line();
  825.     } else
  826.       TEClick(
  827.         here,
  828.         shift,
  829.         gl.TEH);
  830. }
  831.  
  832. void doMouse(THExecRef xecRef);
  833. void doMouse(xecRef)
  834. THExecRef xecRef;
  835. {
  836.     Point here;
  837.     ControlHandle actl;
  838.     int part;
  839.     int double_count;
  840.     here=((*xecRef)->xMousePt);
  841.     GlobalToLocal(&here);
  842.     double_count=is_double(here);
  843.     part=FindControl(here,gl.win,&actl);
  844.     if (part==NIL) {
  845.         if (PtInRect(here,&(*gl.TEH)->viewRect))
  846.             do_teclick(
  847.                 double_count,
  848.                 here,
  849.                 ((*xecRef)->xShift));
  850.     } else if (part==inThumb) {
  851.         TrackControl(actl,here, 0L);
  852.         ScrollTextToMatchControl();
  853.     }
  854.     else
  855.         TrackControl(actl,here,&ScrollProc);
  856.  
  857. }
  858.  
  859. void doKill(THExecRef xecRef);
  860. void doKill(xecRef)
  861. THExecRef xecRef;
  862. {
  863. }
  864.  
  865. void doDismiss(THExecRef xecRef);
  866. void doDismiss(xecRef)
  867. THExecRef xecRef;
  868. {
  869.     close_window();
  870. }
  871.  
  872. void doStdMenuEvt(THExecRef xecRef);
  873. void doStdMenuEvt(xecRef)
  874. THExecRef xecRef;
  875. {
  876.     SysBeep(100);
  877. }
  878.  
  879. pascal void exec_main(xecCode,xecRef)
  880. short xecCode;
  881. THExecRef xecRef;
  882. {
  883.     GrafPtr savePort;
  884.     if((!gl.AreActive)&&
  885.         (xecCode==xCtlIdle))
  886.             return;
  887.     GetPort(&savePort);
  888.     if(gl.win!=NIL)
  889.         SetPort(gl.win);
  890.     switch(xecCode) {
  891.         case xCtlIdle    :doIdle    (xecRef);break;
  892.         case xCtlSend    :doSend    (xecRef);break;
  893.         case xCtlReceive:doReceive(xecRef);break;
  894.         case xCtlFilter    :doFilter(xecRef);break;
  895.         case xCtlInvoke    :doInvoke(xecRef);break;
  896.         case xCtlUnload    :doUnload(xecRef);break;
  897.         case xCtlCommand:doCommand(xecRef);break;
  898.         case xCtlActivate:doActivate(xecRef);break;
  899.         case xCtlDraw    :doDraw(xecRef);break;
  900.         case xCtlKey    :doKey(xecRef);break;
  901.         case xCtlMouse    :doMouse(xecRef);break;
  902.         case xCtlKill    :doKill(xecRef);break;
  903.         case xCtlDismiss:doDismiss(xecRef);break;
  904.         case xCtlStdMenuEvt:doStdMenuEvt(xecRef);break;
  905.         default:
  906.             break;
  907.     }
  908.     SetPort(savePort);
  909. }
  910.